import datetime, turbogears, turbogears.database, sqlobject
from datetime import datetime
from turbogears.database import PackageHub
from sqlobject import *
from sqlobject.inheritance import InheritableSQLObject
from turbogears import identity 

hub = PackageHub("uberwiki")
__connection__ = hub

# class YourDataClass(SQLObject):
#     pass

# identity models.
class Visit(SQLObject):
    class sqlmeta:
        table = "visit"

    visit_key = StringCol(length=40, alternateID=True,
                          alternateMethodName="by_visit_key")
    created = DateTimeCol(default=datetime.now)
    expiry = DateTimeCol()

    def lookup_visit(cls, visit_key):
        try:
            return cls.by_visit_key(visit_key)
        except SQLObjectNotFound:
            return None
    lookup_visit = classmethod(lookup_visit)

class VisitIdentity(SQLObject):
    visit_key = StringCol(length=40, alternateID=True,
                          alternateMethodName="by_visit_key")
    user_id = IntCol()


class Group(SQLObject):
    """
    An ultra-simple group definition.
    """

    # names like "Group", "Order" and "User" are reserved words in SQL
    # so we set the name to something safe for SQL
    class sqlmeta:
        table = "tg_group"

    group_name = UnicodeCol(length=16, alternateID=True,
                            alternateMethodName="by_group_name")
    display_name = UnicodeCol(length=255)
    created = DateTimeCol(default=datetime.now)

    # collection of all users belonging to this group
    users = RelatedJoin("User", intermediateTable="tg_user_group",
                        joinColumn="group_id", otherColumn="user_id")

    # collection of all permissions for this group
    permissions = RelatedJoin("Permission", joinColumn="group_id", 
                              intermediateTable="tg_group_permission",
                              otherColumn="permission_id")


class User(SQLObject):
    """
    Reasonably basic User definition. Probably would want additional attributes.
    """
    # names like "Group", "Order" and "User" are reserved words in SQL
    # so we set the name to something safe for SQL
    class sqlmeta:
        table = "tg_user"

    user_name = UnicodeCol(length=16, alternateID=True,
                           alternateMethodName="by_user_name")
    email_address = UnicodeCol(length=255, alternateID=True,
                               alternateMethodName="by_email_address")
    display_name = UnicodeCol(length=255)
    password = UnicodeCol(length=40)
    created = DateTimeCol(default=datetime.now)

    # groups this user belongs to
    groups = RelatedJoin("Group", intermediateTable="tg_user_group",
                         joinColumn="user_id", otherColumn="group_id")

    def _get_permissions(self):
        perms = set()
        for g in self.groups:
            perms = perms | set(g.permissions)
        return perms

    def _set_password(self, cleartext_password):
        "Runs cleartext_password through the hash algorithm before saving."
        password_hash = identity.encrypt_password(cleartext_password)
        self._SO_set_password(password_hash)

    def set_password_raw(self, password):
        "Saves the password as-is to the database."
        self._SO_set_password(password)



class Permission(SQLObject):
    permission_name = UnicodeCol(length=16, alternateID=True,
                                 alternateMethodName="by_permission_name")
    description = UnicodeCol(length=255)

    groups = RelatedJoin("Group",
                        intermediateTable="tg_group_permission",
                         joinColumn="permission_id", 
                         otherColumn="group_id")

############################################################

class Node(InheritableSQLObject):
    definition = UnicodeCol(length=255, default='')
    facts = MultipleJoin('Fact')
    referenced_by = RelatedJoin('Fact')
    formulas = RelatedJoin('Formula')
    names = MultipleJoin('Name')
    
    @property
    def str_names(self):
        return [str(name) for name in self.names]


    @staticmethod
    def byName(str):
        return Name.byName(str).node

class Name(SQLObject):
    name = StringCol(alternateID=True, length=50, default='')
    node = ForeignKey('Node') 

    def __init__(self, name, *k, *kw):
        self.name = name.title()

    def byName(self, name):
        name = name.title()
        SQLObject(self, name)

    def __str__(self):
        return self.name

class Fact(SQLObject):
    #nodes = RelatedJoin('Node')
    references = RelatedJoin('Node')
    text = UnicodeCol()
    node = ForeignKey('Node')
    #user = ForeignKey('User')

    def __str__(self):
        import ubermarkup
        return ubermarkup.markup(self.text)
    
class FormulaEncoding(SQLObject):
    name = UnicodeCol(length=31)
    def get_encoding_func(self):
        return lambda x: x

    def decode(self, text):
        func = self.get_encoding_func()
        return func(text)

class Formula(Node):
    text = UnicodeCol()
    encoding = ForeignKey('FormulaEncoding')
    nodes = RelatedJoin('Node')   #nodes *referancing* this formula
    
    def decode(self):
        return self.encoding.decode(self.text)

